<?php

namespace common\validators;

use Yii;
use yii\base\InvalidConfigException;
use common\components\wechat\MpWechat;

/**
 * 敏感词过滤
 * WordFilterValidator validates that the attribute value is a valid idcard number.
 *
 * @author emhome <emhome@163.com>
 * @since 2.0
 */
class WordFilterValidator extends \yii\validators\Validator {

    /**
     * @var string|array|\Closure additional filter to be applied to the DB query used to check the existence of the attribute value.
     * This can be a string or an array representing the additional query condition (refer to [[\yii\db\Query::where()]]
     * on the format of query condition), or an anonymous function with the signature `function ($query)`, where `$query`
     * is the [[\yii\db\Query|Query]] object that you can modify in the function.
     */
    public $filter = 'wechatMp';

    /**
     * @var BaseObject
     */
    private $_filter;

    /**
     * {@inheritdoc}
     */
    public function init() {
        parent::init();
        $this->initFilterInstance();
        if ($this->message === null) {
            $this->message = '{attribute}包含违规词汇信息，可能存在潜在风险';
        }
    }

    /**
     * Validates existence of the current attribute based on relation name
     * @param \yii\db\ActiveRecord $model the data model to be validated
     * @param string $attribute the name of the attribute to be validated.
     */
    protected function initFilterInstance() {
        $filter = Yii::$app->get($this->filter, false);
        if (!$filter) {
            if ($this->filter instanceof \Closure) {
                $filter = Yii::createObject($this->filter);
            } else {
                throw new InvalidConfigException("Unknown filter name: $this->filter");
            }
        }
        $this->_filter = $filter;
    }

    /**
     * Validates the specified object.
     * @param \yii\base\Model $model the data model being validated
     * @param array|string|null $attributes the list of attributes to be validated.
     * Note that if an attribute is not associated with the validator - it will be
     * ignored. If this parameter is null, every attribute listed in [[attributes]] will be validated.
     */
    public function validateAttributes($model, $attributes = null) {
        $attributes = $this->getValidationAttributes($attributes);
        foreach ($attributes as $attribute) {
            Yii::error($attribute, __METHOD__);
            $skip = $this->skipOnError && $model->hasErrors($attribute) || $this->skipOnEmpty && $this->isEmpty($model->$attribute);
            if (!$skip) {
                if ($this->when === null || call_user_func($this->when, $model, $attribute)) {
                    $this->validateAttribute($model, $attribute);
                }
            }
        }
    }

    /**
     * {@inheritdoc}
     */
    public function validateAttribute($model, $attribute) {
        if (!$this->checkContent($model->$attribute)) {
            $this->addError($model, $attribute, $this->message);
            return;
        }
        parent::validateAttribute($model, $attribute);
    }

    /**
     * {@inheritdoc}
     */
    protected function validateValue($value) {
        return $this->checkContent($value) ? null : [$this->message, []];
    }

    /**
     * @param mixed $value the data value to be checked.
     */
    private function checkContent($value) {
        $filter = $this->_filter;
        if ($filter instanceof MpWechat) {
            return $filter->checkMsgSec($value);
        }
        return true;
    }

}
